/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author cuilifeng
 */
import java.util.*;

public abstract class AbstractNeuralNetwork implements NeuralNetwork {

    protected double weights[][][];      //三维数组存储权重：weights[层][输入神经元][输出神经元]
    protected double biases[][];     //二维数组存储偏置：biases[层][神经元]
    protected Random random = new Random();  //创建一个随机数生成器对象，用于生成各种随机数。

    public AbstractNeuralNetwork() {                //构造函数
        weights = new double[3][][];      //三层权重
        biases = new double[3][];        //三层偏置

        // 三层权重初始化
        weights[0] = new double[2][4];
        weights[1] = new double[4][4];
        weights[2] = new double[4][1];

        biases[0] = new double[4];
        biases[1] = new double[4];
        biases[2] = new double[1];

        // 改进的权重初始化
        initializeWeights();
    }

    protected void initializeWeights() {
        for (int i = 0; i < weights.length; i++) {
            int inputSize = weights[i].length;
            int outputSize = weights[i][0].length;
            
            // Xavier初始化
            double scale = Math.sqrt(2.0 / (inputSize + outputSize));
            
            for (int j = 0; j < weights[i].length; j++) {
                for (int k = 0; k < weights[i][j].length; k++) {
                    weights[i][j][k] = random.nextGaussian() * scale;
                }
            }
            Arrays.fill(biases[i], 0.0);   //偏置初始化为0
        }
    }

    protected double sigmoid(double x) {
        return 1.0 / (1.0 + Math.exp(-x));
    }

    @Override
    public double predict(double input[]) {
        double current[] = input;

        // 前2层隐藏层使用sigmoid激活函数
        for (int layer = 0; layer < 2; layer++) {
            double output[] = new double[biases[layer].length];

            for (int neuron = 0; neuron < biases[layer].length; neuron++) {
                double sum = biases[layer][neuron];
                for (int i = 0; i < current.length; i++) {
                    sum += current[i] * weights[layer][i][neuron];
                }
                output[neuron] = sigmoid(sum);
            }
            current = output;
        }

        // 输出层使用线性激活（直接返回加权和）
        double sum = biases[2][0];
        for (int i = 0; i < current.length; i++) {
            sum += current[i] * weights[2][i][0];
        }
        return sum;  // 不使用sigmoid，直接返回线性输出
    }

    @Override
    public double calculateLoss(double inputs[][], double targets[]) {
        double total = 0;
        for (int i = 0; i < inputs.length; i++) {
            double predict = predict(inputs[i]);
            double error = predict - targets[i];
            total += error * error;
        }
        return total / inputs.length;
    }

    @Override
    public double[] getParameters() {
        int count = 0;
        for (int i = 0; i < weights.length; i++) {
            count += weights[i].length * weights[i][0].length + biases[i].length;
        }

        double params[]= new double[count];
        int index = 0;

        for (int i = 0; i < weights.length; i++) {
            for (int j = 0; j < weights[i].length; j++) {
                for (int k = 0; k < weights[i][j].length; k++) {
                    params[index++] = weights[i][j][k];
                }
            }
            for (int j = 0; j < biases[i].length; j++) {
                params[index++] = biases[i][j];
            }
        }

        return params;
    }

    @Override
    public void setParameters(double[] params) {
        int index = 0;
        for (int i = 0; i < weights.length; i++) {
            for (int j = 0; j < weights[i].length; j++) {
                for (int k = 0; k < weights[i][j].length; k++) {
                    weights[i][j][k] = params[index++];
                }
            }
            for (int j = 0; j < biases[i].length; j++) {
                biases[i][j] = params[index++];
            }
        }
    }
}